package com.wolf.etl.core.database;

import com.alibaba.druid.pool.DruidDataSource;
import com.wolf.etl.model.EtlDataSourceModel;
import com.wolf.etl.service.IEtlDataSourceService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author sdyang
 * @create 2019-04-06 10:40
 **/
@Component("DynamicService")
public class DynamicService {

    private static final Logger logger = LoggerFactory.getLogger(DynamicService.class);

    private static final String logger_prefix = "wolf-etl#com.wolf.etl.core.database#DynamicService";

    @Autowired
    private Environment env;
    @Autowired
    private DefaultListableBeanFactory beanDefinitionRegistry;
    @Autowired
    private IEtlDataSourceService dataSourceService;

    private static final Object DATASOURCE_TYPE_DEFAULT = "com.alibaba.druid.pool.DruidDataSource";

    private ConversionService conversionService = new DefaultConversionService();

    private PropertyValues dataSourcePropertyValues;

    private Map<String, DataSource> customDataSourceMap = new HashMap<>();

    private GenericBeanDefinition beanDefinition = new GenericBeanDefinition();

    private Map<Object, Object> targetDataSources = new HashMap<Object, Object>();

    @PostConstruct
    public void registerBeanDefinitions() {

        // 添加默认数据源
        DataSource defaultDataSource = initDefaultDataSource();
        targetDataSources.put("dataSource", defaultDataSource);
        DynamicDataSourceContextHolder.dataSourceIds.add("dataSource");

        // 添加更多数据源
        customDataSourceMap = initCustomDataSource();
        targetDataSources.putAll(customDataSourceMap);
        for (String key : customDataSourceMap.keySet()) {
            DynamicDataSourceContextHolder.dataSourceIds.add(key);
        }


        // 创建DynamicDataSource
//        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(DynamicDataSource.class);
        beanDefinition.setSynthetic(true);
        MutablePropertyValues mpv = beanDefinition.getPropertyValues();
        mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);
        mpv.addPropertyValue("targetDataSources", targetDataSources);

        beanDefinitionRegistry.registerBeanDefinition("dataSource", beanDefinition);
    }

    /**
     * 初始化默认数据源
     *
     * @return
     */
    private DataSource initDefaultDataSource() {
        DataSource defaultDataSource;
        RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "spring.datasource.");

        DataSourceParam param = new DataSourceParam();
        param.setDrive_class_name(propertyResolver.getProperty("driver-class-name"));
        param.setUrl(propertyResolver.getProperty("url"));
        param.setUsername(propertyResolver.getProperty("username"));
        param.setPassword(propertyResolver.getProperty("password"));

        defaultDataSource = buildDataSource(param);

        return defaultDataSource;
    }


    /**
     * 初始化自定义数据源
     *
     * @return
     */
    private Map<String, DataSource> initCustomDataSource() {

        Map<String, DataSource> dataSourceMap = new HashMap<String, DataSource>();

        List<EtlDataSourceModel> datasources = dataSourceService.findAll();

        for (EtlDataSourceModel model : datasources) {

            if (model.getStatus() != 1) {
                continue;
            }
            DataSource dataSource = null;

            DataSourceParam param = new DataSourceParam();
            param.setUrl(model.getUrl());
            param.setUsername(model.getUsername());
            param.setPassword(model.getPassword());
            param.setDrive_class_name(model.getDriver_class_name());

            dataSource = buildDataSource(param);

            dataSourceMap.put(model.getId() + "", dataSource);
        }

        return dataSourceMap;
    }

    /**
     * 添加数据源（从数据库加载）
     *
     * @param datasource_id
     * @return
     */
    public boolean addCustomDataSource(String datasource_id) {

        if (DynamicDataSourceContextHolder.containsDataSource(datasource_id)) {
            DynamicDataSourceContextHolder.setDataSourceType(datasource_id);
            return true;
        }

        EtlDataSourceModel ds = dataSourceService.findById(Long.parseLong(datasource_id));

        if (ds == null) {
            return false;
        }

        //未启用
        if (ds.getStatus() != 1) {
            return false;
        }
        DataSourceParam param = new DataSourceParam();
        param.setUrl(ds.getUrl());
        param.setUsername(ds.getUsername());
        param.setPassword(ds.getPassword());
        param.setDrive_class_name(ds.getDriver_class_name());
        System.out.println(ds.getDriver_class_name());

        DataSource dataSource = buildDataSource(param);

        targetDataSources.put(ds.getId() + "", dataSource);

        DynamicDataSourceContextHolder.dataSourceIds.add(ds.getId() + "");

        MutablePropertyValues mpv = beanDefinition.getPropertyValues();
        mpv.addPropertyValue("defaultTargetDataSource", initDefaultDataSource());
        mpv.addPropertyValue("targetDataSources", targetDataSources);

        beanDefinitionRegistry.registerBeanDefinition("dataSource", beanDefinition);

        return true;
    }

    public DataSource getById(String datasource_id) {
        DataSource dataSource = null;

        try {

            if (StringUtils.isEmpty(datasource_id)) {
                System.out.println("使用默认数据源");
                datasource_id = "dataSource";
            }

            addCustomDataSource(datasource_id);

            dataSource = (DataSource) targetDataSources.get(datasource_id);

            // 切换为主数据源  added by sdyang 2019-12-05
            DynamicDataSourceContextHolder.setDefault();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataSource;
    }

    /**
     * @param datasource_id
     * @return
     */
    public Connection getConnectionById(String datasource_id) {

        DataSource dataSource = null;

        Connection connection = null;

        try {

            if (StringUtils.isEmpty(datasource_id)) {
                System.out.println("使用默认数据源");
                datasource_id = "dataSource";
            }

            addCustomDataSource(datasource_id);

            dataSource = (DataSource) targetDataSources.get(datasource_id);

            connection = dataSource.getConnection();
            if (connection == null) {
                System.out.println(" connection is null");
            }

            // 切换为主数据源  added by sdyang 2019-12-05
            DynamicDataSourceContextHolder.setDefault();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }

    /**
     * 构建数据源
     *
     * @param param
     * @return
     */
    public DataSource buildDataSource(DataSourceParam param) {
        try {
            Object type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource

            Class<? extends DataSource> dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);

            String driverClassName = param.getDrive_class_name();
            String url = param.getUrl();
            String username = param.getUsername();
            String password = param.getPassword();

            DefaultDataSourceBuilder factory = DefaultDataSourceBuilder.create().driverClassName(driverClassName).url(url)
                    .username(username).password(password).validationQuery(param.getDialect().getValidationQuery()).type(dataSourceType);
            DruidDataSource dataSource = (DruidDataSource) factory.build();
            dataSource.setFilters("stat,wall");


            //绑定更多信息
            RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);
            dataBinder.setConversionService(conversionService);
            dataBinder.setIgnoreNestedProperties(false);//false
            dataBinder.setIgnoreInvalidFields(false);//false
            dataBinder.setIgnoreUnknownFields(true);//true
            if (dataSourcePropertyValues == null) {
                Map<String, Object> rpr = new RelaxedPropertyResolver(env, "spring.datasource").getSubProperties(".");
                Map<String, Object> values = new HashMap<>(rpr);
                // 排除已经设置的属性
                values.remove("type");
                values.remove("driverClassName");
                values.remove("url");
                values.remove("username");
                values.remove("password");
                values.remove("validationQuery");
                dataSourcePropertyValues = new MutablePropertyValues(values);
            }

            dataBinder.bind(dataSourcePropertyValues);

            return dataSource;

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }


}
